home *** CD-ROM | disk | FTP | other *** search
- /*
- * ij.h - device-independent input jacks for VL
- *
- * this is a simple hack API. you pick a VL device. you get a list of
- * available input jacks as text strings. you pick one. the hack will
- * create a path from a properly configured video source node to the
- * drain node you give. hopefully someday the VL will offer this
- * functionality built-in so that developers do not have to deal with
- * this level of device-dependence.
- *
- * this hack also lets you pick the default jack and see what that was.
- *
- * WARNING this version has not been tested for all jacks for all devices.
- */
-
- #include <dmedia/vl.h>
-
- typedef struct _IJhandle *IJhandle;
-
- /*
- * open a handle to use to pick input jacks. at this point you
- * specify a VLServer, and you specify what device you'll be using
- * (VL_ANY for the default device).
- *
- * if you'd just like to present a list of device names, you can use
- * something like this snippet:
- *
- {
- VLDevList devlist;
-
- vlGetDeviceList(vlServer, &devlist);
-
- for (dv=0; dv < (int)devlist.numDevices; dv++)
- printf("the device with VLDev %d is called [%s]\n",
- devlist.devices[dv].dev,
- devlist.devices[dv].name);
- }
- *
- * the VLDev (not the index dv) is what you pass to ijOpenHandle.
- *
- * during this call, ij may scan the hardware to see which flavor of a
- * board you have, and which options are really present. instead of
- * exposing the (often misleading) VL device name to the user, you can
- * get ij to give you a much more meaningful name (the marketing name
- * for the flavor of board the user has installed) with this snippet:
- *
- {
- VLDevList devlist;
-
- vlGetDeviceList(vlServer, &devlist);
-
- for (dv=0; dv < (int)devlist.numDevices; dv++)
- {
- VLDev dev = devlist.devices[dv].dev;
-
- VLNode drain_node = vlGetNode(vlServer, VL_DRN, VL_MEM, VL_ANY);
- IJhandle h = ijOpenHandle(vlServer, dev, drain_node);
-
- printf("device with VLDev %d: VL calls it [%s]"
- " but it's really [%s]\n",
- devlist.devices[dv].dev,
- devlist.devices[dv].name
- ijGetDeviceName(h));
-
- ijCloseHandle(h);
- }
- }
- *
- * ij will use the VLServer and VLDev passed in for other functions
- * you call in the lifetime of this IJhandle.
- *
- * NOTE: you must also specify the handle to a drain node of the kind you
- * will be using (screen, memory, etc.). this VLNode is not saved in
- * the IJhandle and thus it will not be used by future ij calls unless
- * you pass the same VLNode in again. ij may need to use this drain_node
- * in order to probe the device to find out its capabilities, and in
- * order to translate VL_ANY to an actual default device. In these cases,
- * ijOpenHandle will actually create, set up, and destroy a path using your
- * drain_node. The VL leaves us no alternative to doing this. ij uses
- * VL_READ_ONLY, VL_READ_ONLY when setting up the path, so in theory this
- * should not interfere with the VL preemption mechanism. There is one
- * more caveat that results from this: VL has a limitation where it cannot
- * deal with the same VLNode handle being used on a path on different
- * devices. Therefore, once you pass drain_node into ijOpenHandle,
- * you should never use that node handle again. You can call vlGetNode
- * with the same arguments to get a new handle that refers to the same
- * resources. This is shown in the code snippet above.
- *
- * NOTE: in most cases, the hardware inventory information available
- * to ij is derived from a scan done at BOOT TIME. Therefore, if
- * the user plugs in some dongle, break-out-box, or digital camera
- * after the machine has booted, it may not be included in ij's list
- * of jacks (the user must reboot to get the jacks listed).
- */
- IJhandle ijOpenHandle(VLServer svr, /* required */
- VLDev device, /* VL_ANY for default device */
- VLNode drain_node); /* drain node you'll use on path */
-
- /*
- * ijCloseHandle deallocates ij's resources for this handle:
- * it does not destroy any VL nodes or paths.
- */
- void ijCloseHandle(IJhandle h);
-
- /*
- * returns the VLDev chosen. useful if you specified VL_ANY to ijOpenHandle
- */
- int ijGetVLDev(IJhandle h);
-
- /*
- * get a name suitable to describe THIS flavor of the board you have
- * selected. This will return the appropriate string in cases like
- * "Indy Video" vs. "Galileo Video".
- *
- * string belongs to ij and is valid as long as this IJhandle is alive.
- */
- char *ijGetDeviceName(IJhandle h);
-
- /*
- * get number of jacks for this handle
- */
- int ijGetNumJacks(IJhandle h);
-
- /*
- * get a textual description of each input jack.
- *
- * string belongs to ij and is valid as long as this IJhandle is alive.
- *
- * idx should range from 0 to ijGetNumJacks() - 1
- */
- char *ijGetJackName(IJhandle h, int idx); /* from 0 to NumJacks-1 */
-
- /*
- * how to choose a jack:
- *
- * you pick a jack by specifying an index idx from 0 to ijGetNumJacks() - 1,
- * or you can pick the jack currently selected in vcp by passing VL_ANY
- * for idx.
- *
- * use the following functions in this way to create a properly
- * configured path from that jack to your specified drain_node:
- *
- {
- ... create IJhandle h and drain node drain_node, pick idx ...
- int node_number = ijGetNodeNumber(h, idx);
- VLDev device = ijGetVLDev(h);
- VLNode source_node = vlGetNode(svr, VL_SRC, VL_VIDEO, node_number);
- VLPath path = vlCreatePath(svr, device, source_node, drain_node);
-
- if (node_number < 0 || source_node < 0 || path < 0)
- return FALSE;
-
- if (vlSetupPaths(svr, (VLPathList)&path, 1, VL_SHARE, VL_SHARE) < 0)
- { vlDestroyPath(svr, path); return FALSE; }
-
- if (ijConfigurePath(h, idx,
- source_node, drain_node, path,
- node_number, ret_idx))
- { vlDestroyPath(svr, path); return FALSE; }
- }
- *
- * as you can see here, jack selection in the VL consists of two parts:
- * first you must choose the right VLNode and set up a path containing that
- * node, and then you must properly configure the node. in the VL, each
- * VL_VIDEO, VL_SRC node can serve one or more input jacks, and the choice
- * of video node and its required settings are totally device-dependent.
- * ij handles the device-dependent aspects for you.
- *
- * ijGetNodeNumber() returns a video source node number which lets
- * you create the video source node.
- *
- * once you have created the node and path and set up the path,
- * you now pass control back to ijConfigurePath() which does the
- * necessary vlSetControl()s to configure your path to input
- * data from the requested jack.
- *
- * the index of the actual jack chosen is returned in *ret_idx if
- * ret_idx is non-NULL. this is how you tell which is the default jack.
- *
- * ijGetNodeNumber() and ijConfigurePath return <0 on failure.
- * no error return values are provided now, except for VLErrno.
- *
- * you can call this routine as many times as you like with different
- * arguments. calling this function does not change the state of the
- * IJhandle in any way. ij does not store the VLPath, VLNodes, index,
- * or node number it returns in the handle at all.
- *
- * VL CRAP:
- *
- * Q: why doesn't ij provide a quicky routine that just returns you an
- * already-configured node and path?
- *
- * A: to do this, IJ would need to create the source node, because
- * the video source node number varies by jack in the VL.
- *
- * then, ij would need to create the path, because we need to set controls
- * on the nodes we create, and VL only lets you set controls on a node if
- * you also specify the path the node is on! argh!
- *
- * then, ij would need to set up the paths, since the VL only lets you set
- * controls on a path which is set up! argh!! vlSetupPaths() is a
- * critical operation whose arguments and return value are of great
- * importance to an app; it would be difficult to do this inside ij
- * without removing critical control from the app. what's worse,
- * some apps want to pass more than one path at a time to
- * vlSetupPaths so that the resource allocation is atomic. this
- * would not be possible if ij did the path setup.
- *
- * Q: why isn't there a function you can call to simply return the current
- * jack rather than creating a path?
- *
- * A: because in VL, you CAN'T get the current jack without creating a path.
- * argh!
- *
- * the notion of "current jack" in VL is complicated. the current jack
- * selected on vcp is the current jack on the current VL default source
- * node. ij determines the current default souce node by creating a
- * device path, setting it up VL_READ_ONLY, VL_READ_ONLY, reading
- * its node number from the control VL_DEFAULT_SOURCE, and destroying
- * the path. Then it gets a handle to that node, opens up a path on
- * that node, and determines which jack is the current jack on that node
- * by getting various device-dependent VL controls on that node.
- * it is truly unfortunate that VL users must deal with this.
- *
- */
- int ijGetNodeNumber(IJhandle h, int idx);
-
- int ijConfigurePath(IJhandle h, int idx,
- VLNode source_node, VLNode drain_node, VLPath path,
- int node_number, int *ret_idx);
-
-
- /*
- * when you get a VLControlChanged event, pass in the type of the
- * VL control which changed, and this function will return 1
- * if that control could affect the choice of input jack, or 0
- * if not. see the Q and A below to see why you would want to
- * do this.
- */
- int ijDoesControlAffectInputJack(IJhandle h, VLControlType type) ;
-
-
- /*
- * Some questions and answers about input jack selection:
- *
- * Q: what to do when the user chooses a different jack in vcp?
- *
- * A: when this happens, one of two things occurs:
- *
- * - if the user changes the default source node in vcp (usually
- * this looks like a "default in" menu), your app will receive a
- * VLDefaultSource event.
- * - if the user changes the current jack on the default source node,
- * your app will receive a VLControlChanged event for the relevant controls.
- * many menus on vcp could change the current jack on the default source
- * node.
- *
- * if the default source node changes, and you want to track vcp,
- * you MUST destroy and recreate the node and path, since the current
- * jack now resides on a new VLNode.
- *
- * if the jack on the default source node changes, then technically you
- * don't have to destroy and recreate the node and path, but you might as well
- * do it anyway.
- *
- * so, to track changes in vcp,
- *
- * - add VLDefaultSourceMask|VLControlChangedMask to your event mask.
- * - when you receive a VLDefaultSource event, destroy your node and path,
- * and call ijGetNodeCreatePath() again with an argument of VL_ANY for idx.
- * ijGetNodeCreatePath() will return the index of the newly chosen jack.
- * - when you receive a VLControlChanged event, check to see whether the
- * control that changed could affect the current input jack, and if so,
- * do the same as if you had received a VLDefaultSource event.
- * Determining whether the VLControlChanged event could cause an input
- * jack change is---you guessed it---device-dependent. Use
- * ijDoesControlAffectInputJack() to determine this (see above).
- *
- *
- * Q: what if I want my app to be totally independent of vcp?
- *
- * A: sorry, bud. the system was just not designed that way.
- * on most SGI devices, the available input jacks are separated
- * into groups, and the hardware is only designed to take in data
- * from ONE jack per group at a time. for example, an ev1 board has
- * up to 4 analog video inputs, but only one of those inputs can be
- * used for video->memory or video->screen paths at a time. This is
- * true even if the paths in question are owned by totally separate
- * processes--the choice of a jack from the group of analog input
- * jacks device-global. So, when a user goes and changes the
- * "analog input source" setting on vcp, or any other app running on
- * the system changes the same control, your app WILL start getting
- * data from a different jack, and you cannot control or lock out this
- * behavior in any way.
- *
- * the "groups" of jacks are represented in the VL as separate VLNodes.
- * the selection of a jack within a particular VLNode is done by
- * setting controls on that node, usually (but not always) VL_MUXSWITCH.
- * on all devices so far, the VL_MUXSWITCH (or comparable) setting on a
- * VLNode is device-global, meaning that it affects all other VLNodes
- * with the same node number. Only when different jacks are present
- * on different VLNodes can you use them simultaneously.
- *
- * this lame behavior can be found in: vino, ev1, sirius, and impactvid.
- * future devices may or may not exhibit this behavior.
- *
- * given this, the best you can achieve is to be "sort of" independent
- * of vcp. sometimes, when people mess with vcp, it will affect your
- * app. sometimes, it will not.
- *
- * our video hardware and VL software have left us with only one way
- * of avoiding this usability nightmare, one way to present consistent
- * behavior: make your app input from whatever jack is selected in vcp.
- * if the user selects a new jack in vcp, then your app changes
- * immediately. this behavior would be consistently true regardless
- * of which jack selection control the user futzed with---your app
- * would not behave differently if the user changed "analog input source"
- * versus "default in," as many do now. The GUI user knows nothing
- * about VL nodes or VL_MUXSWITCH controls, and it is silly expecting
- * the user to understand such concepts when all they want to do
- * is input video from ONE jack (which is what the vast majority
- * want to do). If the user is doing a task where they really need
- * two input jacks, then sure, go ahead and expose the subtleties.
- * but if your app just needs to pick one input jack, and it doesn't
- * specifically need to pick a different jack than other apps which
- * are running, it may not be worthwhile for you to try and make your
- * app independent of vcp. you will only present a user interface
- * which is inconsistent with vcp and confusing.
- *
- *
- * Q: what to do when the user chooses a different jack in my app?
- *
- * A: destroy the node and the path yourself, and call
- * ijGetNodeCreatePath again.
- *
- * on the same theory of keeping your app consistent with vcp,
- * you would presumably want to make sure that vcp reflected
- * the new default input jack. as with the question above,
- * SOME of vcp's controls will automatically reflect your
- * new choice of jack, because they are device-global controls.
- * but not all of them. In order to keep vcp consistent, you
- * would have to set the default source node to the node number
- * of the newly selected jack. This would mean setting the
- * VL_DEFAULT_SOURCE parameter on the device node for the
- * device (XXX will VL let you do this? checking...)
- *
- */
-
-
-
-